import Watcher from "./observe/watcher";
import { createElementVnode, createTextVnode, createCommentVnode } from "./vdom";
import { patch } from "./vdom/patch";

export function initLifeCycle(Vue) {
    // 将虚拟DOM渲染成真实DOM
    Vue.prototype._update = function (vnode) {
        // 获取真实dom
        const el = this.$el;

        // pacth既有初始化的功能又有更新的功能
        this.$el = patch(el, vnode);
    }

    // 接收节点信息 _c('div',{},...children)
    Vue.prototype._c = function () {
        return createElementVnode(this, ...arguments);
    }

    // 接收文本信息 _v(text)
    Vue.prototype._v = function () {
        return createTextVnode(this, ...arguments);
    }

    // 接收注释信息 _e(comment)
    Vue.prototype._e = function () {
        return createCommentVnode(this, ...arguments);
    }

    // 接收响应式数据，取值返回
    Vue.prototype._s = function (value) {
        // 不是对象直接返回
        if (typeof value !== 'object') return value;

        // 将对象转成文本进行返回
        return JSON.stringify(value);
    }

    // 产生虚拟DOM
    Vue.prototype._render = function () {
        // 创建一个新的虚拟DOM
        return this.$options.render.call(this);
    }
}

export function mountComponent(vm, el) {
    // 将 el 挂载到 vm.$el 上
    vm.$el = el;

    /*
        1.调用 render 方法产生虚拟 DOM
        2.根据虚拟 DOM 产生真实 DOM 中
        3.插到 el 元素中
    */

    // 更新组件
    function updateComponent() {
        vm._update(vm._render());
    }

    // 创建 watcher 观察者
    new Watcher(vm, updateComponent, { render: true });
}

/*
    1.创造响应式数据
    2.模板转换成ast语法树
    3.将ast语法树转换成render函数
    4.后续每次更新数据可以只执行render函数（无需在执行ast转化过程）

    render函数会产生虚拟dom（使用响应式数据）
    根据虚拟dom渲染真实dom
*/

// 调用钩子函数
export function callHook(vm, hook) {
    const handlers = vm.$options[hook];
    if (handlers) {
        handlers.forEach(handler => handler.call(vm))
    }
}
